home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 31
/
Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso
/
Aminet
/
dev
/
c
/
vbccwossrc.lha
/
vbcc
/
pasm
/
output_ehf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-07
|
12KB
|
416 lines
/* $VER: pasm output_ehf.c V1.2 (24.10.98)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997-98 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-98 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v1.2 (24.10.98) phx
* An empty section with reloc symbols will no longer be deleted.
* Replaced obsolete R_PPC_TOC16 by real R_PPC_SDAREL16.
* v1.1d (27.09.98) phx
* fopen() uses binary mode "b" for windoze/msdog compatibility.
* v1.1b (05.07.98) phx
* Support for Chip/Fast-Ram sections (new .section-attributes
* "C" and "F").
* v1.0 (02.05.98) phx
* Empty EHF objects contain at least an empty CODE-hunk.
* v0.9 (24.03.98) phx
* XDef for global symbols with type = @object was missing.
* Use the name set by ".file" for the unit name and not the
* one set by ".ident", which has no meaning for EHF.
* v0.7 (02.01.98) phx
* Sections after a section with HUNK_EXT were 4 bytes too large.
* Output format OFMT_ADOS support. The difference between ADOS and
* and EHF is, that ADOS uses HUNK_CODE instead HUNK_PPC_CODE and
* doesn't support any PPC-specific relocations and references types.
* This makes it possible to link simple PowerPC programs with an
* old linker, like BLink, SLink or PhxLnk.
* v0.4 (02.07.97) phx
* File created.
*/
#define OUTPUT_EHF_C
#include "ppcasm.h"
#include "ehf.h"
struct XRefNode {
struct node n;
char *sym_name;
uint8 ref_type;
int noffsets;
struct list xreflist;
};
static char *output_name;
static int nsecs = 0;
static bool exthunk;
void output_ehf(struct GlobalVars *);
static void reloc_hunk(FILE *,struct Section *,uint8,uint32);
static void unsupp_relocs(struct Section *);
static void ext_header(FILE *);
static void ext_refs(FILE *,struct GlobalVars *,struct Section *);
static void ext_defs(FILE *,struct GlobalVars *,uint32,uint8,uint32);
static uint32 word_strlen(char *);
static void write_name(FILE *,struct GlobalVars *,char *);
static void fwalign(FILE *,struct GlobalVars *,uint32);
static void fw(FILE *,void *,size_t);
static void fw4(FILE *,uint32);
void output_ehf(struct GlobalVars *gv)
{
struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
struct Symbol *symchain;
uint32 index;
bool ehfmode = gv->output==OFMT_EHF;
bool empty = TRUE;
FILE *fp;
/* assign an index to each valid section */
while (nextsec = (struct Section *)sec->n.next) {
if (!(sec->flags & SF_DISCARD) && sec->size > 0)
sec->index = nsecs++;
sec = nextsec;
}
/* create output file */
output_name = gv->dest_name;
if (fp = fopen(output_name,"wb")) { /* create output file */
fw4(fp,HUNK_UNIT);
if (gv->file) {
fw4(fp,word_strlen(gv->file)); /* unit name */
write_name(fp,gv,gv->file);
}
else
fw4(fp,0);
/* section loop */
sec = (struct Section *)gv->sectionlist.first;
while (nextsec = (struct Section *)sec->n.next) {
exthunk = FALSE;
if (!(sec->flags & SF_DISCARD) &&
(sec->size > 0 || (sec->flags & SF_HASSYMS))) {
uint32 styp = HUNK_DATA; /* default type */
index = sec->index;
empty = FALSE;
/* section name */
fw4(fp,HUNK_NAME);
fw4(fp,word_strlen(sec->name));
write_name(fp,gv,sec->name);
/* section type and size */
switch(sec->type) {
case ST_CODE:
styp = ehfmode ? HUNK_PPC_CODE : HUNK_CODE;
break;
case ST_DATA:
styp = HUNK_DATA;
break;
case ST_UDATA:
styp = HUNK_BSS;
break;
default: /* section type not supported in EHF/ADOS */
error(52,sec->name,(int)sec->type);
break;
}
if (sec->flags & SF_CHIP)
styp |= HUNKF_CHIP;
else if (sec->flags & SF_FAST)
styp |= HUNKF_FAST;
fw4(fp,styp);
fw4(fp,(uint32)(sec->size+3)>>2);
/* write section contents */
if (!(sec->flags & SF_UNINITIALIZED)) {
fw(fp,sec->contents,(uint32)sec->size);
fwalign(fp,gv,(uint32)sec->size);
}
/* relocation hunks */
reloc_hunk(fp,sec,R_PPC_ADDR32,HUNK_ABSRELOC32);
/* @@@ reloc_hunk(fp,sec,R_PPC_ADDR16,HUNK_ABSRELOC16); */
if (ehfmode)
reloc_hunk(fp,sec,R_PPC_REL24,HUNK_RELRELOC26);
reloc_hunk(fp,sec,R_PPC_REL14,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL14_BRTAKEN,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL14_BRNTAKEN,HUNK_RELRELOC16);
reloc_hunk(fp,sec,R_PPC_REL32,HUNK_RELRELOC32);
reloc_hunk(fp,sec,R_PPC_SDAREL16,HUNK_DREL16);
unsupp_relocs(sec); /* print unsupported relocations */
/* external references and global definitions */
ext_refs(fp,gv,sec);
ext_defs(fp,gv,index,SYM_RELOC,EXT_DEF);
if (index == 0) /* put absolute definitions in first HUNK_EXT */
ext_defs(fp,gv,0xffff,SYM_ABS,EXT_ABS);
if (exthunk)
fw4(fp,0); /* close HUNK_EXT block */
/* symbol table */
ext_defs(fp,gv,index,SYM_RELOC,EXT_SYMB);
fw4(fp,HUNK_END); /* end of this hunk */
}
sec = nextsec;
}
if (empty) { /* there was not a single section */
fw4(fp,ehfmode ? HUNK_PPC_CODE : HUNK_CODE);
fw4(fp,0);
fw4(fp,HUNK_END);
}
fclose(fp);
}
else
error(25,output_name); /* unable to create output file */
}
static void reloc_hunk(FILE *fp,struct Section *sec,uint8 r,uint32 ehfrel)
/* generate an EHF relocation hunk for a specific reloc type */
{
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
struct list **rlist=alloc(nsecs*sizeof(struct list *));
int *rcnt=alloczero(nsecs*sizeof(int)); /* reloc cnt for all sections */
bool hunk_required=FALSE;
int i;
for (i=0; i<nsecs; i++) { /* empty reloc lists for each section */
rlist[i] = alloc(sizeof(struct list));
initlist(rlist[i]);
}
while (nextrel = (struct Reloc *)rel->n.next) {
if (rel->type == r) {
/* move reloc node of correct type into relocssect's rlist */
remnode(&rel->n);
addtail(rlist[rel->relocsect->index],&rel->n);
rcnt[rel->relocsect->index]++;
hunk_required = TRUE;
}
rel = nextrel;
}
if (hunk_required) { /* there's at least one relocation */
fw4(fp,ehfrel); /* reloc hunk id */
for (i=0; i<nsecs; i++) {
if (rcnt[i]) {
fw4(fp,(uint32)rcnt[i]); /* number of relocations */
fw4(fp,(uint32)i); /* section index */
/* store relocation offsets */
while(rel = (struct Reloc *)remhead(rlist[i])) {
fw4(fp,(uint32)rel->offset);
free(rel);
}
}
}
fw4(fp,0); /* no more relocation entries */
}
/* free dynamically allocated rlists and rcnt array */
for (i=0; i<nsecs; free(rlist[i++]));
free(rcnt);
}
static void unsupp_relocs(struct Section *sec)
{
struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
while (nextrel = (struct Reloc *)rel->n.next) {
error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,sec->name);
rel = nextrel;
}
}
static void ext_header(FILE *fp)
{
if (!exthunk) {
exthunk = TRUE;
fw4(fp,HUNK_EXT);
}
}
static void ext_refs(FILE *fp,struct GlobalVars *gv,struct Section *sec)
{
struct list xnodelist; /* xrefs with same ref. type and symbol name */
struct XRefNode *xn,*nextxn;
struct XReference *xref;
initlist(&xnodelist);
while (xref = (struct XReference *)remhead(&sec->xreflist)) {
char *name = xref->xsymbol->name; /* name of xref'ed symbol */
uint8 rtype = xref->type;
/* ELF32 -> EHF referen